package de.openkanban.server.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import de.openkanban.server.dao.BoardDao;
import de.openkanban.server.domain.Activity;
import de.openkanban.server.domain.Board;
import de.openkanban.server.domain.User;
import de.openkanban.shared.util.StatusCodes;

@Repository
public class BoardDaoImpl implements BoardDao {

	@PersistenceContext
	private EntityManager entityManager;

	@Override
	@Transactional
	public Board createBoard(Board board, Long userId) {
		User user = entityManager.find(User.class, userId);
		board.getBoardUser().add(user);
		entityManager.persist(board);
		return board;
	}

	@Override
	public Board getBoardById(Long boardId) {
		Board board = entityManager.find(Board.class, boardId);
		return board;
	}

	@Override
	public Board getBoardByActivityId(Long parentActivityId) {
		Query query = entityManager.createQuery("SELECT b from Board b JOIN b.activities a WHERE a.activityId=:activityId");
		query.setParameter("activityId", parentActivityId);
		@SuppressWarnings("unchecked")
		List<Board> boardResultList = query.getResultList();
		if (boardResultList.isEmpty()) {
			return new Board();
		}
		return boardResultList.iterator().next();
	}

	@Override
	public List<Board> getAll() {
		Query query = entityManager.createQuery("SELECT b FROM Board b");
		@SuppressWarnings("unchecked")
		List<Board> boardList = (List<Board>) query.getResultList();
		return boardList;
	}

	@Override
	@Transactional
	public Board removeBoard(Board board) {
		entityManager.remove(board);
		return board;
	}

	@Override
	@Transactional
	public Activity addActivityToBoard(Long parentBoardId, Activity newActivity) {
		Board board = entityManager.find(Board.class, parentBoardId);
		if (board != null) {
			entityManager.persist(newActivity);
			board.getActivities().add(newActivity);
			entityManager.merge(board);
			return newActivity;
		}
		return null;
	}

	@Override
	@Transactional
	public Activity removeFromBoard(Long parentBoardId, Activity newActivity) {
		Board board = entityManager.find(Board.class, parentBoardId);
		board.getActivities().remove(newActivity);
		entityManager.merge(board);
		return newActivity;
	}

	@Override
	@Transactional
	public Board updateBoard(Board board) {
		entityManager.merge(board);
		return board;
	}

	@Override
	@Transactional
	public StatusCodes addContactToBoard(Long parentBoardId, User newUser) {
		Board board = entityManager.find(Board.class, parentBoardId);
		if (board != null) {
			board.getBoardUser().add(newUser);
			entityManager.merge(board);
			return StatusCodes.OK;
		}
		return StatusCodes.DATABASE_ERROR;
	}

	@Override
	@Transactional
	public StatusCodes removeContactFromBoard(Long parentBoardId, Long userId) {
		User userToRemove = entityManager.find(User.class, userId);
		Board board = entityManager.find(Board.class, parentBoardId);
		if (board != null) {
			board.getBoardUser().remove(userToRemove);
			entityManager.merge(board);
			return StatusCodes.OK;
		}
		return StatusCodes.DATABASE_ERROR;
	}

	@Override
	public Board getDefaultBoardByUserId(Long userId) {
		Query query = entityManager
				.createQuery("SELECT b FROM Board b JOIN b.boardUser u WHERE u.userId=:userId ORDER BY b.boardId");
		query.setParameter("userId", userId);
		query.setMaxResults(1);

		@SuppressWarnings("unchecked")
		List<Board> boardList = query.getResultList();

		if (boardList.size() != 1) {
			return null;
		}

		return (Board) boardList.iterator().next();
	}

	@Override
	public Long getNextBoardId(Long currentBoardId, Long userId) {
		Query query = entityManager
				.createQuery("SELECT b.boardId FROM Board b JOIN b.boardUser u WHERE u.userId=:userId AND b.boardId>:currentBoardId ORDER BY b.boardId");
		query.setParameter("currentBoardId", currentBoardId);
		query.setParameter("userId", userId);
		query.setMaxResults(1);

		@SuppressWarnings("unchecked")
		List<Long> boardIdList = query.getResultList();
		if (boardIdList.size() != 1) {
			return null;
		}

		return (Long) boardIdList.iterator().next();
	}

	@Override
	public Long getPriorBoardId(Long currentBoardId, Long userId) {
		Query query = entityManager
				.createQuery("SELECT b.boardId FROM Board b JOIN b.boardUser u WHERE u.userId=:userId AND b.boardId<:currentBoardId ORDER BY b.boardId DESC");
		query.setParameter("currentBoardId", currentBoardId);
		query.setParameter("userId", userId);
		query.setMaxResults(1);

		@SuppressWarnings("unchecked")
		List<Long> boardIdList = query.getResultList();

		if (boardIdList.size() != 1) {
			return null;
		}

		return (Long) boardIdList.iterator().next();
	}
}
